﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace C4F.DevKit.Speech.Controls
{
    [ToolboxItem(true), ToolboxBitmap(typeof(TextToSpeech))]
    /// <summary>
    /// A control for using the SpeechAPI to read text from a textbox or a file.
    /// </summary>
    public partial class TextToSpeech : UserControl
    {
        #region Private Variables

        private SapiManager _sapiManager = null;
        private bool _paused = false;

        private const string DESIGNER_CATEGORY = "Speech";

        #endregion Private Variables

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the TextToSpeech control.
        /// </summary>
        public TextToSpeech()
        {
            InitializeComponent();

            if (!this.DesignMode)
            {
                InitializeControl();                
            }
        }

        #endregion Constructors

        #region Public Properties

        /// <summary>
        /// The text to be set as the text to read.
        /// </summary>
        [Browsable(true), Category(DESIGNER_CATEGORY)]
        public string SpeechText
        {
            get { return this.tbTextToSpeech.Text; }
            set { this.tbTextToSpeech.Text = value == null ? string.Empty : value; }
        }
        
        [Browsable(true), Category(DESIGNER_CATEGORY)]
        public bool IsSsml
        {
            get { return chkSsmlText.Checked; }
            set { chkSsmlText.Checked = value; }
        }

        /// <summary>
        /// The SAPI Manager to be used by this control.
        /// </summary>
        [Browsable(true), Category(DESIGNER_CATEGORY)]
        public SapiManager SapiManager
        {
            get { return _sapiManager; }
            set
            {
                _sapiManager = value;

                if (_sapiManager != null)
                    _sapiManager.StateChanged += new SapiManager.SapiStateChnageEventHandler(sapi_StateChanged);
            }
        }

        #endregion Public Properties

        #region Event Handlers

        private void btnToWav_Click(object sender, EventArgs e)
        {
            try
            {
                _sapiManager.ToWave(tbTextToSpeech.Text, chkSsmlText.Checked);
            }
            catch
            {
                MessageBox.Show("Error occurred while converting to Wave file.!!", "SpeechGUI", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void tbTextToSpeech_TextChanged(object sender, EventArgs e)
        {
            OnTextChanged();            
        }        

        private void btnStop_Click(object sender, EventArgs e)
        {
            try
            {
                OnStopSpeaking();
                
            }
            catch (Exception ex)
            {
                DisplayError("The operation could not be stopped.", ex);
            }
        }

        private void btnPause_Click(object sender, EventArgs e)
        {
            try
            {
                OnPause();
            }
            catch (Exception ex)
            {
                DisplayError("The operation could not be paused.", ex);
            }
        }

        private void btnSpeak_Click(object sender, EventArgs e)
        {
            try
            {
                OnSpeak();
            }
            catch (Exception ex)
            {
                DisplayError("The speak operation could not be started.", ex);
            }
        }

        private void btnResume_Click(object sender, EventArgs e)
        {
            try
            {
                OnResumeSpeaking();
            }
            catch (Exception ex)
            {
                DisplayError("The operation could not be resumed.", ex);
            }
        }
        private void btnLoadFile_Click(object sender, EventArgs e)
        {
            try
            {
                OnLoadFile();
            }
            catch (Exception ex)
            {
                DisplayError("File could not be loaded.", ex);
            }
        }

        /// <summary>
        /// Called when the state of the SapiManager has changed.
        /// </summary>
        private void sapi_StateChanged()
        {
            ChangeButtonState();
        }

        #endregion Event Handlers

        #region Private

        /// <summary>
        /// Initializes the control for use.
        /// </summary>
        private void InitializeControl()
        {
            try
            {
                _paused = false;
                this.btnToWav.Enabled = false;
                this.btnSpeak.Enabled = false;
                this.btnPause.Enabled = false;
                this.btnResume.Enabled = false;
                this.btnStop.Enabled = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SpeechGUI", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Updates the UI to change the state of certain buttons.
        /// </summary>
        private void ChangeButtonState()
        {
            switch (_sapiManager.State)
            {
                case SynthesizerState.Paused:
                    this.btnSpeak.Enabled = false;
                    this.btnPause.Enabled = false;
                    this.btnResume.Enabled = true;
                    this.btnToWav.Enabled = false;
                    this.btnStop.Enabled = true;
                    this.tbTextToSpeech.Enabled = false;
                    this.chkSsmlText.Enabled = false;
                    break;
                case SynthesizerState.Ready:
                    this.btnSpeak.Enabled = true;
                    this.btnPause.Enabled = false;
                    this.btnResume.Enabled = false;
                    this.btnToWav.Enabled = true;
                    this.btnStop.Enabled = false;
                    this.tbTextToSpeech.Enabled = true;
                    this.chkSsmlText.Enabled = true;
                    break;
                case SynthesizerState.Speaking:
                    this.btnSpeak.Enabled = false;
                    this.btnPause.Enabled = true;
                    this.btnResume.Enabled = false;
                    this.btnToWav.Enabled = false;
                    this.btnStop.Enabled = true;
                    this.tbTextToSpeech.Enabled = false;
                    this.chkSsmlText.Enabled = false;
                    break;
            }
        }

        /// <summary>
        /// Displays the exception error.
        /// </summary>
        /// <param name="message">The message to be shown.</param>
        /// <param name="ex">The exception to be displayed along with the error message.</param>
        private void DisplayError(string message, Exception ex)
        {
            if (message == null)
                message = string.Empty;

            string exMessage = ex == null ? string.Empty : string.Concat( "\n\n" , ex.ToString());
            MessageBox.Show(string.Format("{0}{1}", message, ex.ToString()), "TextToSpeech", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private void OnLoadFile()
        {
            tbTextToSpeech.Text = _sapiManager.GetTextFromFile();
        }

        /// <summary>
        /// Pauses the speak operation
        /// </summary>
        private void OnPause()
        {
            if (!_paused)
            {
                _sapiManager.PauseSpeaking();
                _paused = true;
            }
        }

        /// <summary>
        /// Resumes the speak operation
        /// </summary>
        private void OnResumeSpeaking()
        {
            if (_paused)
            {
                _sapiManager.ResumeSpeaking();
                _paused = false;
            }
        }

        /// <summary>
        /// Starts the speak operation
        /// </summary>
        private void OnSpeak()
        {
            if (!chkSsmlText.Checked)
            {
                _sapiManager.Speak(tbTextToSpeech.Text);
            }
            else
            {
                _sapiManager.SpeakSsml(tbTextToSpeech.Text);
            }
        }

        /// <summary>
        /// Stops the speak operation
        /// </summary>
        private void OnStopSpeaking()
        {
            _sapiManager.StopSpeaking();
        }

        /// <summary>
        /// Updates UI when the text is changed.
        /// </summary>
        private void OnTextChanged()
        {
            btnToWav.Enabled = btnSpeak.Enabled = tbTextToSpeech.Text != string.Empty;
        }

        #endregion Private       
    }
}